<?php //-->
/*
 * This file is part of the Eden package.
 * (c) 2009-2011 Christian Blanquera <cblanquera@gmail.com>
 *
 * Copyright and license information can be found at LICENSE.txt
 * distributed with this package.
 */

/**
 * Abstractly defines a layout of available methods to
 * connect to and query a database. This class also lays out 
 * query building methods that auto renders a valid query
 * the specific database will understand without actually 
 * needing to know the query language.
 *
 * @package    Eden
 * @category   sql
 * @author     Christian Blanquera <cblanquera@gmail.com>
 * @version    $Id: abstract.php 1 2010-01-02 23:06:36Z blanquera $
 */
class Front_Mysql extends Eden_Mysql {
	/* Constants
	-------------------------------*/
	/* Public Properties
	-------------------------------*/
	/* Protected Properties
	-------------------------------*/
	protected $_cache		= NULL;
	protected $_results		= array();
	protected $_cacheCount 	= array(0, 0);
	
	/* Private Properties
	-------------------------------*/
	/* Get
	-------------------------------*/
	public static function i() {
		return self::_getMultiple(__CLASS__);
	}
	
	/* Magic
	-------------------------------*/
	public function __construct($host, $name, $user, $pass = NULL, $port = NULL) {
		parent::__construct($host, $name, $user, $pass, $port);
		$root = front()->registry()->get('path', 'root');
		$path = realpath($root.'/cache/database');
		$this->_cache = Eden_Cache::i($path);
	}
	
	/* Public Methods
	-------------------------------*/
	/**
	 * Queries the database
	 * 
	 * @param string query
	 * @param array binded value
	 * @return array|object
	 */
	public function query($query, array $binds = array()) {
		if(strpos(strtolower($query), 'insert into') === 0 
		|| strpos(strtolower($query), 'update') === 0
		|| strpos(strtolower($query), 'delete from') === 0) {
			//get the table
			$table = str_replace('insert into ', '', strtolower($query));
			$table = str_replace('update ', '', $table);
			$table = str_replace('delete from ', '', $table);
			list($table, $trash) = explode(' ', $table, 2);
			
			$keys = $this->_cache->getKeys();
			
			//invalidate all selects
			foreach($this->_results as $key => $result) {
				$lower = strtolower($key);
				if(strpos($lower, 'from '.$table) !== false 
				|| strpos($lower, 'join '.$table) !== false
				|| preg_match("/from\s[a-zA-z]+\.".$table."\s/i", $lower)
				|| preg_match("/join\s[a-zA-z]+\.".$table."\s/i", $lower)) {
					unset($this->_results[$key]);
				}
			}
			
			foreach($keys as $key) {
				$lower = strtolower($key);
				if(strpos($lower, 'from '.$table) !== false 
				|| strpos($lower, 'join '.$table) !== false
				|| preg_match("/from\s[a-zA-z]+\.".$table."\s/i", $lower)
				|| preg_match("/join\s[a-zA-z]+\.".$table."\s/i", $lower)) {
					$this->_cache->remove($key);
				}
			}
		}
		
		if(strpos(strtolower($query), 'select') !== 0) {
			return parent::query($query, $binds);
		}
		
		$key = $this->_getCacheKey($query, $binds);
		
		if(isset($this->_results[$key])) {
			$this->_cacheCount[0]++;
			$this->_binds = array();
			return $this->_results[$key];
		} else if($this->_cache->keyExists($key)) {
			$this->_cacheCount[0]++;
			$this->_binds = array();
			return $this->_cache->get($key);
		}
		
		$results = parent::query($query, $binds);
		$this->_cacheCount[1]++;
		$this->_results[$key] = $results;
		$this->_cache->set($key, time().'-'.front()->uid(), $results);
		
		return $results;
	}
	
	public function getCacheCount() {
		return $this->_cacheCount;
	}
	
	/* Protected Methods
	-------------------------------*/
	protected function _getCacheKey($query, $binds) {
		return $query.json_encode($binds);
	}
	
	/* Private Methods
	-------------------------------*/
}
